package com.tencent.yolov5ncnn
// Tencent is pleased to support the open source community by making ncnn available.
//
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// https://opensource.org/licenses/BSD-3-Clause
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.

import android.Manifest
import android.content.Context
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.hardware.Camera
import android.location.Location
import android.location.LocationListener
import android.location.LocationManager
import android.media.ExifInterface
import android.os.Build
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.SurfaceHolder
import android.view.SurfaceView
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast
import androidx.annotation.RequiresApi
import androidx.core.app.ActivityCompat
import androidx.fragment.app.Fragment
import com.blankj.utilcode.util.ImageUtils
import com.blankj.utilcode.util.ThreadUtils.runOnUiThread
import com.tencent.yolov5ncnn.MediaFileUtils.getOutputMediaFile
import java.io.BufferedReader
import java.io.BufferedWriter
import java.io.File
import java.io.FileReader
import java.io.FileWriter
import java.io.IOException
import java.util.Timer
import java.util.TimerTask


class phoneCamera : Fragment(), SurfaceHolder.Callback {
    private var imageView: ImageView? = null
    private var bitmap: Bitmap? = null
    private var yourSelectedImage: Bitmap? = null
    private var cameraHelper: CameraHelper? = null
    private var surfaceView: SurfaceView? = null
    private val cameraId = Camera.CameraInfo.CAMERA_FACING_BACK
    private val yolov5ncnn = YoloV5Ncnn()

    val timer = Timer()
    private var root: View? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    }

    /** Called when the activity is first created.  */
    @RequiresApi(Build.VERSION_CODES.Q)
    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        super.onCreate(savedInstanceState)
        if (root == null) {
            root = inflater.inflate(R.layout.fragment_phone_camera, container, false)
        }
        getOutputMediaFile(1)
        val ret_init = yolov5ncnn.Init(requireActivity().assets)
        if (!ret_init) {
            Log.e("MainActivity", "yolov5ncnn Init failed")
        }

        //相机初始化
        cameraHelper = CameraHelper(requireActivity(), cameraId, 1920, 1080)
        cameraHelper!!.setOnPreviewListener { data: ByteArray?, camera: Camera? -> }
        surfaceView = root?.findViewById(R.id.surface_view)
        surfaceView!!.getHolder().addCallback(this)
        //相机初始化结束
        val buttonImage = root?.findViewById<View>(R.id.buttonImage) as Button
        buttonImage.setOnClickListener {
            cameraHelper!!.switchCamera()
        }
        //持续拍摄
        val buttonHaveShot = root?.findViewById<View>(R.id.buttonHaveShot) as Button
        val buttonStopShot = root?.findViewById<View>(R.id.buttonStopShot) as Button
        buttonHaveShot.setOnClickListener {
            buttonHaveShot.visibility = View.GONE
            buttonStopShot.visibility = View.VISIBLE
            timer.schedule(timerTask, 0, 1200) // 参数：(定时任务，延迟时间（毫秒），间隔时间（毫秒）)
        }
        //停止拍摄
        buttonStopShot.setOnClickListener {
            buttonHaveShot.visibility = View.VISIBLE
            buttonStopShot.visibility = View.GONE
            timer.cancel() // 关闭定时器
        }

        //oncreateView结束
        return root
    }


    //获取定位
    @RequiresApi(Build.VERSION_CODES.Q)
    private fun getLocation(pictureFile: File? = null) {

        var latitude: Double
        var longitude: Double
        val REQUEST_LOCATION_PERMISSION = 1
        var isGPSEnabled: Boolean = false
        var locationManager: LocationManager? = null
        var locationListener: LocationListener? = null
        locationManager =
            requireActivity().getSystemService(Context.LOCATION_SERVICE) as LocationManager

        locationListener = object : LocationListener {
            override fun onLocationChanged(location: Location) {

//                runOnUiThread {
                // 在这里执行与 UI 相关的操作
                latitude = location.latitude
                longitude = location.longitude
                val exifInterface: ExifInterface? = pictureFile?.let { ExifInterface(it) }
                exifInterface?.setAttribute(
                    ExifInterface.TAG_GPS_LATITUDE,
                    doubleToDMSString(latitude)
                )
                exifInterface?.setAttribute(
                    ExifInterface.TAG_GPS_LONGITUDE,
                    doubleToDMSString(longitude)
                )
                exifInterface?.saveAttributes()
//                }


                // 如果使用了 GPS 定位，则移除网络定位的请求
                if (isGPSEnabled) {
                    locationManager!!.removeUpdates(this)
                }
            }

            override fun onProviderEnabled(provider: String) {

            }

            override fun onProviderDisabled(provider: String) {}

            override fun onStatusChanged(provider: String, status: Int, extras: Bundle) {}
        }
        runOnUiThread {
            if (locationManager!!.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
                // 如果 GPS 可用，则使用 GPS 定位
                isGPSEnabled = true

                if (ActivityCompat.checkSelfPermission(
                        requireContext(),
                        Manifest.permission.ACCESS_FINE_LOCATION
                    ) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
                        requireContext(),
                        Manifest.permission.ACCESS_COARSE_LOCATION
                    ) != PackageManager.PERMISSION_GRANTED
                ) {
                    // 如果权限未被授予，请求权限
                    ActivityCompat.requestPermissions(
                        requireActivity(),  // 使用 Fragment 所在的 Activity
                        arrayOf(
                            Manifest.permission.ACCESS_FINE_LOCATION,
                            Manifest.permission.ACCESS_COARSE_LOCATION
                        ),
                        REQUEST_LOCATION_PERMISSION // 可以是任何整数值，用于标识请求
                    )
                }

                locationManager.requestLocationUpdates(
                    LocationManager.GPS_PROVIDER,
                    0,
                    0f,
                    locationListener as LocationListener
                )



                Log.d("asdf", "${pictureFile}")
                if (isGPSEnabled) {
                    isGPSEnabled = false
                    locationManager.removeUpdates(locationListener as LocationListener)
                    locationManager.requestLocationUpdates(
                        LocationManager.NETWORK_PROVIDER,
                        0,
                        0f,
                        locationListener as LocationListener
                    )
                }

            } else {
                // 如果 GPS 不可用，则直接使用网络定位
                locationManager.requestLocationUpdates(
                    LocationManager.NETWORK_PROVIDER,
                    0,
                    0f,
                    locationListener as LocationListener
                )
            }
        }
    }

    //判断有没有人
    fun containsKeyboardLabel(objArray: Array<YoloV5Ncnn.Obj>, target: String = "human"): Boolean {
        // 遍历对象数组
        for (obj in objArray) {
            // 如果某个对象的 label 属性值是 "keyboard"，返回 true
            if (obj.label == target) {
                return true
            }
        }
        // 如果遍历完整个数组都没有找到 label 是 "keyboard" 的对象，则返回 false
        return false
    }

    // 创建一个 TimerTask 对象，定义定时任务
    val timerTask = object : TimerTask() {
        @RequiresApi(Build.VERSION_CODES.Q)
        override fun run() {
            // 定时任务要执行的操作
            cameraHelper!!.takePicture(
                { rotatedBitmap ->
                    bitmap = rotatedBitmap
                    yourSelectedImage = bitmap!!.copy(Bitmap.Config.ARGB_8888, true)
                    val objects = yolov5ncnn.Detect(yourSelectedImage, true)

//                    showObjects(objects, true)
                    val have: Boolean = containsKeyboardLabel(objects, "keyboard")
                    val pictureFile: File? = getOutputMediaFile(true)
                    ImageUtils.save(rotatedBitmap, pictureFile, Bitmap.CompressFormat.JPEG)
                    //保存为csv
                    val filePath = pictureFile?.parent// 替换为你要检查的文件路径
                    val file = File(filePath + "/pic.csv")
                    if (file.exists()) {
                       val picname=pictureFile?.name
                        val row = listOf(picname, "false", "false")
                        FileWriter(file, true).buffered().use { out ->
                            // Write header
                out.write(row.joinToString(","))
                            out.newLine()
                        }
                    } else {
                       Toast.makeText(getContext(),"文件缺失，重启",Toast.LENGTH_SHORT).show()
                    }
                    //保存结束
                    null
                },
                { res: Exception? -> null })
        }
    }

    fun readFile(filePath: String): String? {
        val file = File(filePath)
        if (!file.exists() || !file.isFile) {
            return null
        }

        val stringBuilder = StringBuilder()
        try {
            val reader = BufferedReader(FileReader(file))
            var line: String?
            while (reader.readLine().also { line = it } != null) {
                stringBuilder.append(line).append("\n")
            }
            reader.close()
        } catch (e: IOException) {
            e.printStackTrace()
            return null
        }

        return stringBuilder.toString()
    }
    override fun surfaceCreated(holder: SurfaceHolder) {
        cameraHelper!!.startPreview(holder)
    }

    override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
        // Your implementation for surfaceChanged in Java
    }

    override fun surfaceDestroyed(holder: SurfaceHolder) {
//        cameraHelper!!.stopPreview()
    }

    @RequiresApi(Build.VERSION_CODES.Q)
    private fun showObjects(objects: Array<YoloV5Ncnn.Obj>?, save: Boolean = false) {
        if (objects == null) {
//            imageView!!.setImageBitmap(bitmap)
            return
        }

        // draw objects on bitmap
        val rgba = bitmap!!.copy(Bitmap.Config.ARGB_8888, true)

        val colors = intArrayOf(
            Color.rgb(54, 67, 244),
            Color.rgb(99, 30, 233),
            Color.rgb(176, 39, 156),
            Color.rgb(183, 58, 103),
            Color.rgb(181, 81, 63),
            Color.rgb(243, 150, 33),
            Color.rgb(244, 169, 3),
            Color.rgb(212, 188, 0),
            Color.rgb(136, 150, 0),
            Color.rgb(80, 175, 76),
            Color.rgb(74, 195, 139),
            Color.rgb(57, 220, 205),
            Color.rgb(59, 235, 255),
            Color.rgb(7, 193, 255),
            Color.rgb(0, 152, 255),
            Color.rgb(34, 87, 255),
            Color.rgb(72, 85, 121),
            Color.rgb(158, 158, 158),
            Color.rgb(139, 125, 96)
        )

        val canvas = Canvas(rgba)

        val paint = Paint()
        paint.style = Paint.Style.STROKE
        paint.strokeWidth = 4f

        val textbgpaint = Paint()
        textbgpaint.color = Color.WHITE
        textbgpaint.style = Paint.Style.FILL

        val textpaint = Paint()
        textpaint.color = Color.BLACK
        textpaint.textSize = 96f
        textpaint.textAlign = Paint.Align.LEFT

        for (i in objects.indices) {
            paint.color = colors[i % 19]

            canvas.drawRect(
                objects[i].x,
                objects[i].y,
                objects[i].x + objects[i].w,
                objects[i].y + objects[i].h,
                paint
            )

            // draw filled text inside image
            run {
                val text =
                    objects[i].label + " = " + String.format("%.1f", objects[i].prob * 100) + "%"
                val text_width = textpaint.measureText(text)
                val text_height = -textpaint.ascent() + textpaint.descent()

                var x = objects[i].x
                var y = objects[i].y - text_height
                if (y < 0) y = 0f
                if (x + text_width > rgba.width) x = rgba.width - text_width

                canvas.drawRect(x, y, x + text_width, y + text_height, textbgpaint)
                canvas.drawText(text, x, y - textpaint.ascent(), textpaint)
            }
        }
        if (save) {

            val pictureFile: File? = getOutputMediaFile(1)


            ImageUtils.save(rgba, pictureFile, Bitmap.CompressFormat.JPEG)

//            val exifInterface: ExifInterface? = pictureFile?.let { ExifInterface(it) }
//            exifInterface?.setAttribute(ExifInterface.TAG_GPS_LATITUDE ,doubleToDMSString(3.4))
//            exifInterface?.setAttribute(ExifInterface.TAG_GPS_LONGITUDE , doubleToDMSString(29.0854))
//            exifInterface?.saveAttributes()
            getLocation(pictureFile)

        } else {
            imageView!!.setImageBitmap(rgba)
        }

    }

    //转换度分秒
    fun doubleToDMSString(value: Double): String {
        val degrees = value.toInt()
        val minutesDouble = (value - degrees) * 60
        val minutes = minutesDouble.toInt()
        val secondsDouble = (minutesDouble - minutes) * 60
        val seconds = secondsDouble.toInt()
        return "$degrees/1,$minutes/1,$seconds/1"
//    return "$degrees/1"
    }

    companion object {
        private const val SELECT_IMAGE = 1
    }
}